#include "stdafx.h"
#include "CRegionSceneNode.h"

CRegionSceneNode::CRegionSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, vector3di size,
				const core::vector3df& position,
				const core::vector3df& rotation,
				const core::vector3df& scale)
				: ISceneNode(parent, mgr, id, position, rotation, scale), Size(size)
{
	BlockMesh = SceneManager->getGeometryCreator()->createCubeMesh(vector3df(1,1,1));

	VisibleBlocks = 0;
	BlockCount = Size.X * Size.Y * Size.Z;
	Blocks = new ISceneNode*[BlockCount];

	ITexture *t[10];
	for(int i = 0; i < 10; i++)
		t[i] = getTexture(SColor(rand()), mgr->getVideoDriver());

	for(s32 x = 0; x < Size.X; x++)
	{
		for(s32 y = 0; y < Size.Y; y++)
		{
			for(s32 z = 0; z < Size.Z; z++)
			{
				ISceneNode *node = mgr->addCubeSceneNode(1.0f, this, 0, vector3df((f32)x, (f32)y, (f32)z));
				node->setMaterialTexture(0, t[rand() % 10]);
				Blocks[z * Size.Y * Size.X + y * Size.X + x] = node;
			//	this->addChild(node);
			}
		}
	}
	updateBlocks(true);
	//updateBlocks(false);
}

CRegionSceneNode::~CRegionSceneNode()
{
}

void CRegionSceneNode::render()
{
	VisibleBlocks = 0;
	for(u32 i = 0; i < BlockCount; i++)
	{
		if(Blocks[i] != 0 && Blocks[i]->isVisible())
		{
			Blocks[i]->render();
			VisibleBlocks++;
		}
	}
}

void CRegionSceneNode::updateBlocks(bool reset)
{
	u32 c = 0;
	for(s32 x = 0; x < Size.X; x++)
	{
		for(s32 y = 0; y < Size.Y; y++)
		{
			for(s32 z = 0; z < Size.Z; z++)
			{
				ISceneNode *node = getBlock(x, y, z);
				if(node == 0) continue;

				if(reset)
					node->setVisible(true);

				if(x == 0 || x == Size.X-1 || y == 0 || y == Size.Y-1 || z == 0 || z == Size.Z-1)
					continue;
				
				if(reset)
				{
					node->setVisible(false);
					continue;
				}

				if(node->isVisible())
					continue;
				list<ISceneNode*> nodes;
		//		if(x > 0)
					nodes.push_back(getBlock(x-1, y, z));
		//		if(x+1 < Size.X)
					nodes.push_back(getBlock(x+1, y, z));
		//		if(y > 0)
					nodes.push_back(getBlock(x, y-1, z));
		//		if(y+1 < Size.Y)
					nodes.push_back(getBlock(x, y+1, z));
		//		if(z > 0)
					nodes.push_back(getBlock(x, y, z-1));
		//		if(z+1 < Size.Z)
					nodes.push_back(getBlock(x, y, z+1));

				u32 invisible = 0;
				u32 visible = 0;
				list<ISceneNode*>::Iterator it = nodes.begin();
				for(; it != nodes.end(); ++it)
				{
					if((*it) == 0 || !(*it)->isVisible())
						invisible++;
					else
						visible++;
				}
				if(visible > 0 && invisible > 0)
				{
					c++;
					node->setVisible(true);
				}
			}
		}
	}
	printf("updateBlocks %d new visible blocks\n", c);
}

SBlock& CRegionSceneNode::getBlock(u32 x, u32 y, u32 z) const
{
	return Blocks[z * Size.Y * Size.X + y * Size.X + x];
}

ISceneNode** CRegionSceneNode::getSurroundingBlocks(u32 &count)
{
	return 0;
}

void CRegionSceneNode::removeBlock(ISceneNode *block)
{
	for(u32 i = 0; i < BlockCount; i++)
	{
		if(Blocks[i] != 0 && Blocks[i] == block)
		{
			vector3df pos = Blocks[i]->getPosition();
			Blocks[i] = 0;
			block->remove();

			s32 x = (s32)pos.X;
			s32 y = (s32)pos.Y;
			s32 z = (s32)pos.Z;

			list<ISceneNode*> nodes;
			if(x > 0)
				nodes.push_back(getBlock(x-1, y, z));
			if(x+1 < Size.X)
				nodes.push_back(getBlock(x+1, y, z));
			if(y > 0)
				nodes.push_back(getBlock(x, y-1, z));
			if(y+1 < Size.Y)
				nodes.push_back(getBlock(x, y+1, z));
			if(z > 0)
				nodes.push_back(getBlock(x, y, z-1));
			if(z+1 < Size.Z)
				nodes.push_back(getBlock(x, y, z+1));

			list<ISceneNode*>::Iterator it = nodes.begin();
			for(; it != nodes.end(); ++it)
			{
				if((*it) != 0)
					(*it)->setVisible(true);
			}
		}
	}
}